#include <ctime>
#include <sys/types.h>
#include <unistd.h>

#include "BlockQueue.hpp"
#include "Task.hpp"

// C:计算任务
// S:保存任务
template <class C, class S>
class BlockQueues
{
public:
    BlockQueue<C> *_cq;
    BlockQueue<S> *_sq;
};

void *producer(void *args)
{
    // BlockQueue<Task> *bq = static_cast<BlockQueue<Task> *>(args);
    BlockQueue<CalTask> *bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(args))->_cq;
    while (true)
    {
        // 生产者生产数据
        int x = rand() % 10 + 1;
        int y = rand() % 5;
        int opindex = rand() % opArr.size();
        CalTask ct(x, y, opArr[opindex], mymath);
        bq->push(ct);
        cout << "生产者生产任务: " << ct.toTaskString() << endl;
        // cout << "生产者生产：" << data << endl;
        //  此时生产者生产得慢，生产者生产一个，消费者就拿走一个
        sleep(1);
    }

    return nullptr;
}

void *consumer(void *args)
{
    // BlockQueue<Task> *bq = static_cast<BlockQueue<Task> *>(args);
    BlockQueue<CalTask> *c_bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(args))->_cq;
    BlockQueue<SaveTask> *s_bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(args))->_sq;
    while (true)
    {
        // 消费者先从 c_bq拿出数据，再保存在s_bq中
        CalTask ct;
        c_bq->pop(&ct);
        string task = ct();
        cout << "消费者计算任务: " << task << endl;

        SaveTask st(task, Save);
        s_bq->push(st);
        cout << "消费者推送任务成功... " << endl;
        sleep(1);
    }

    // while (true)
    // {
    //     // 消费者消费数据拿出数据
    //     // int data;
    //     // Task t;
    //     // bq->pop(&t);
    //     // cout << "消费者任务：" << t() << endl;

    //     // 此时生产者生产得快，消费者消费得满，只拿走一个
    //     // sleep(1);
    // }

    return nullptr;
}

void *Preserver(void *args)
{
    BlockQueue<SaveTask> *s_bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(args))->_sq;
    while (true)
    {
        // 保存数据到文件中
        SaveTask st;
        s_bq->pop(&st);
        st();
        cout << "保存者保存数据成功... " << endl;
    }

    return nullptr;
}

int main()
{
    srand((unsigned long)time(nullptr) ^ getpid());
    // BlockQueue<Task> *_bq = new BlockQueue<Task>();
    BlockQueues<CalTask, SaveTask> bqs;
    bqs._cq = new BlockQueue<CalTask>();
    bqs._sq = new BlockQueue<SaveTask>();

    pthread_t P[4], C[3], S; // 生产者与消费者
    pthread_create(P, nullptr, producer, &bqs);
    pthread_create(P+1, nullptr, producer, &bqs);
    pthread_create(P+2, nullptr, producer, &bqs);
    pthread_create(P+3, nullptr, producer, &bqs);
    pthread_create(C, nullptr, consumer, &bqs);
    pthread_create(C+1, nullptr, consumer, &bqs);
    pthread_create(C+2, nullptr, consumer, &bqs);
    //pthread_create(&S, nullptr, Preserver, &bqs);

    pthread_join(C[0], nullptr);
    pthread_join(C[1], nullptr);
    pthread_join(C[2], nullptr);
    pthread_join(P[0], nullptr);
    pthread_join(P[1], nullptr);
    //pthread_join(S, nullptr);
    return 0;
}